package com.learn.springframework.aop;

import com.learn.springframework.aop.aspect.Advice;
import com.learn.springframework.aop.support.AdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * 基于JDK动态代理实现
 */
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    private AdvisedSupport config;

    public JdkDynamicAopProxy(AdvisedSupport config) {
        this.config = config;
    }

    @Override
    public Object getProxy() {
        return getProxy(this.getClass().getClassLoader());
//        return Proxy.newProxyInstance(this.getClass().getClassLoader(), this.config.getTargetClass().getInterfaces(), this);
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader,this.config.getTargetClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        Map<String, Advice> advices = this.config.getAdvices(method, this.config.getTargetClass());
        invokeAdvice(advices.get("before"));
        Object returnValue = null;
        try {
            returnValue = method.invoke(this.config.getTarget(), args);
        } catch (Exception e) {
            invokeAdvice(advices.get("afterThrowing"));
            throw e;
        }
        invokeAdvice(advices.get("after"));
        return returnValue;
    }

    private void invokeAdvice(Advice advice) {

        try {
            advice.getAdviceMethod().invoke(advice.getAspect());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
